﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace GaleSong
{
    /// <summary>
    ///     A concrete <see cref="System.Windows.Data.IValueConverter" /> used to covert the bool value to the visibility.
    /// </summary>
    public class BoolToVisibleCollapsedConverter : IValueConverter
    {
        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value produced by the binding source.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                var visible = (bool)value;
                if(parameter != null)
                {
                    visible = !visible;
                }
                Visibility vi = visible ? Visibility.Visible : Visibility.Collapsed;
                return vi;
            }
            catch
            {
                return DependencyProperty.UnsetValue;
            }
        }

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value that is produced by the binding target.</param>
        /// <param name="targetType">The type to convert to.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class ThicknessToDoubleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var thickness = (Thickness)value;
            return thickness.Left;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class NullableImageSourceConverter : IValueConverter
    {
        private static readonly ImageSourceConverter defaultImageSourceConverter = new ImageSourceConverter();
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value == null)
            {
                return null;
            }
            else if(value == DependencyProperty.UnsetValue)
            {
                return Binding.DoNothing;
            }
            try
            {
                return defaultImageSourceConverter.ConvertFrom(value.ToString());
            }
            catch
            {
                return Binding.DoNothing;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    ///     A concrete <see cref="System.Windows.Data.IValueConverter" /> used to covert the enum value to the bool.
    /// </summary>
    public class EnumToBooleanConverter : IValueConverter
    {
        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value produced by the binding source.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null || parameter == null || value == DependencyProperty.UnsetValue || parameter == DependencyProperty.UnsetValue)
            {
                return Binding.DoNothing;
            }

            return value.Equals(parameter);
        }

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value that is produced by the binding target.</param>
        /// <param name="targetType">The type to convert to.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value.Equals(true) ? parameter : Binding.DoNothing;
        }
    }

    /// <summary>
    ///     A concrete <see cref="System.Windows.Data.IValueConverter" /> used to return positive & negatived value.
    /// </summary>
    public class PositiveNegativedConverter : IValueConverter
    {
        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value produced by the binding source.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                var visible = (bool)value;
                if(parameter != null)
                {
                    visible = !visible;
                }
                return visible;
            }
            catch
            {
                return Binding.DoNothing;
            }
        }

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value that is produced by the binding target.</param>
        /// <param name="targetType">The type to convert to.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class WidthPercentageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double percentage = Double.Parse(parameter.ToString(), new CultureInfo("en-US"));
            return ((double)value) * percentage;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    ///     Invertes the <see cref="bool" /> values.
    /// </summary>
    public class BooleanInverterConvertor : IValueConverter
    {
        #region Implementation of IValueConverter

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        /// <param name="value">
        ///     The value produced by the binding source.
        /// </param>
        /// <param name="targetType">
        ///     The type of the binding target property.
        /// </param>
        /// <param name="parameter">
        ///     The converter parameter to use.
        /// </param>
        /// <param name="culture">
        ///     The culture to use in the converter.
        /// </param>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                bool result = !System.Convert.ToBoolean(value, culture);
                return result;
            }
            catch
            {
                return DependencyProperty.UnsetValue;
            }
        }

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        /// <param name="value">
        ///     The value that is produced by the binding target.
        /// </param>
        /// <param name="targetType">
        ///     The type to convert to.
        /// </param>
        /// <param name="parameter">
        ///     The converter parameter to use.
        /// </param>
        /// <param name="culture">
        ///     The culture to use in the converter.
        /// </param>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                bool result = !System.Convert.ToBoolean(value, culture);
                return result;
            }
            catch
            {
                return DependencyProperty.UnsetValue;
            }
        }

        #endregion
    }

    /// <summary>
    ///     A concrete <see cref="System.Windows.Data.IValueConverter" /> used to covert the length.
    /// </summary>
    public class LengthConverter : IValueConverter
    {
        public string Unit { get; set; }

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value produced by the binding source.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value == null || string.IsNullOrEmpty(Unit))
            {
                return value;
            }

            try
            {
                return value + Unit;
            }
            catch
            {
                return Binding.DoNothing;
            }
        }

        /// <summary>
        ///     Converts a value.
        /// </summary>
        /// <param name="value">The value that is produced by the binding target.</param>
        /// <param name="targetType">The type to convert to.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>
        ///     A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class IsNotNullConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (value != null);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new InvalidOperationException("IsNotNullConverter can only be used OneWay.");
        }
    }

    public class GenericBindingConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(!(value is IPart) ||
               parameter == null)
            {
                return null;
            }

            string[] interfaceName = parameter.ToString().Split('.');
            if(interfaceName == null && interfaceName.Length != 2)
            {
                throw new ArgumentException(
                    "The parameter of GenericBindingConverter is not valid, it should be as Interface.Property");
            }

            return value.GetType().GetInterfaceProperty(interfaceName[0], interfaceName[1]).GetValue(value, null);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class ImgaeResourceConverter : IValueConverter
    {
        public static ImgaeResourceConverter Default = new ImgaeResourceConverter();

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value == null || value == DependencyProperty.UnsetValue)
            {
                return DependencyProperty.UnsetValue;
            }

            return new Image
            {
                Source =
                    ImgaeSourceResourceConverter.Default.Convert(value, targetType, parameter, culture) as ImageSource
            };
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class ImgaeSourceResourceConverter : IValueConverter
    {
        public static ImgaeSourceResourceConverter Default = new ImgaeSourceResourceConverter();

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value == null || value == DependencyProperty.UnsetValue)
            {
                return DependencyProperty.UnsetValue;
            }

            return IoC.Get<IResourceService>().GetImage(value.ToString());
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    #region StringEditor Converters

    public class StringEditorProgressWidthConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if(values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue
               || values[2] == DependencyProperty.UnsetValue || values[3] == DependencyProperty.UnsetValue)
            {
                return null;
            }

            var min = (double)values[0];
            var max = (double)values[1];
            var value = (double)values[2];
            var width = (double)values[3];
            if(max <= min || value < min || value > max)
            {
                return null;
            }
            return (value - min) * width / (max - min);
        }

        public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("StringEditorProgressWidthConverter only support OneWay Binding");
        }
    }

    public class StringEditorTextFormatConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if(values[0] == DependencyProperty.UnsetValue
               || values[1] == DependencyProperty.UnsetValue)
            {
                return null;
            }

            var digits = (uint)values[1];

            return string.Format("{0:F" + digits + "}", values[0]);
        }

        public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("StringEditorTextFormatConverter only support OneWay Binding");
        }
    }

    public class StringEditorAngleTextFormatConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if(values[0] == DependencyProperty.UnsetValue
               || values[1] == DependencyProperty.UnsetValue)
            {
                return null;
            }

            var digits = (uint)values[1];

            return string.Format("{0:F" + digits + "}°", values[0]);
        }

        public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("StringEditorTextFormatConverter only support OneWay Binding");
        }
    }

    #endregion
}